/*
 * Copyright 2002-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory.config;

import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.core.AttributeAccessor;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;

/**
 * BeanDefinition 描述了一个 bean 实例，它具有属性值、构造函数参数值以及由具体实现提供的更多信息。
 * <p>这只是一个最小的接口：主要目的是允许{@link BeanFactoryPostProcessor}内省和修改属性值和其他 bean 元数据。
 * @author Juergen Hoeller
 * @author Rob Harrop
 * @since 19.03.2004
 * @see ConfigurableListableBeanFactory#getBeanDefinition
 * @see org.springframework.beans.factory.support.RootBeanDefinition
 * @see org.springframework.beans.factory.support.ChildBeanDefinition
 */
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
	// 我们可以看到，默认只提供 sington 和 prototype 两种，
	// 很多读者可能知道还有 request, session, globalSession, application, websocket 这几种，不过，它们属于基于 web 的扩展。

	/**
	 *	标准单例范围的范围标识符：“singleton”。
	 * 请注意，扩展 bean 工厂可能支持更多范围。
	 * @see #setScope
	 * @see ConfigurableBeanFactory#SCOPE_SINGLETON
	 */
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

	/**
	 *	标准原型范围的范围标识符：“prototype”。
	 * 请注意，扩展 bean 工厂可能支持更多范围。
	 * @see #setScope
	 * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE
	 */
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

	// 下面三个属性，比较不重要，直接跳过吧
	/**
	 * 指示BeanDefinition是应用程序主要部分的角色提示。 通常对应于用户定义的 bean。
	 */
	int ROLE_APPLICATION = 0;

	/**
	 * Role hint indicating that a {@code BeanDefinition} is a supporting
	 * part of some larger configuration, typically an outer
	 * {@link org.springframework.beans.factory.parsing.ComponentDefinition}.
	 * {@code SUPPORT} beans are considered important enough to be aware
	 * of when looking more closely at a particular
	 * {@link org.springframework.beans.factory.parsing.ComponentDefinition},
	 * but not when looking at the overall configuration of an application.
	 */
	int ROLE_SUPPORT = 1;

	/**
	 * Role hint indicating that a {@code BeanDefinition} is providing an
	 * entirely background role and has no relevance to the end-user. This hint is
	 * used when registering beans that are completely part of the internal workings
	 * of a {@link org.springframework.beans.factory.parsing.ComponentDefinition}.
	 */
	int ROLE_INFRASTRUCTURE = 2;


	/**
	 * 设置此 bean 定义的父定义的名称（如果有）。
	 * 这里涉及到 bean 继承，不是 java 继承。一句话就是：继承父 Bean 的配置信息而已
	 */
	void setParentName(@Nullable String parentName);

	/**
	 * 返回此 bean 定义的父定义的名称（如果有）。
	 */
	@Nullable
	String getParentName();

	/**
	 * 指定此 bean 定义的 bean 类名称，将来是要通过反射来生成实例的.
	 * 类名可以在 bean factory 后处理期间修改，通常用它的解析变体替换原始类名。
	 * @see #setParentName
	 * @see #setFactoryBeanName
	 * @see #setFactoryMethodName
	 */
	void setBeanClassName(@Nullable String beanClassName);

	/**
	 * 返回此 bean 定义的当前 bean 类名称。
	 * <p>请注意，这不必是运行时使用的实际类名，以防子定义覆盖/继承其父类的类名。 此外，这可能只是调用工厂方法的类，或者在调用方法的工厂 bean 引用的情况下它甚至可能为空。
	 * 		因此，不要将其视为运行时的明确 bean 类型，而应仅将其用于单个 bean 定义级别的解析目的。
	 * @see #getParentName()
	 * @see #getFactoryBeanName()
	 * @see #getFactoryMethodName()
	 */
	@Nullable
	String getBeanClassName();

	/**
	 * 覆盖此 bean 的目标范围，指定新的范围名称。
	 * @see #SCOPE_SINGLETON
	 * @see #SCOPE_PROTOTYPE
	 */
	void setScope(@Nullable String scope);

	/**
	 * 返回此 bean 的当前目标范围的名称，如果尚不知道，则返回null 。
	 */
	@Nullable
	String getScope();

	/**
	 * 设置这个 bean 是否应该被延迟初始化。
	 * <p>如果为false ，则 bean 将在启动时由执行单例急切初始化的 bean 工厂实例化。
	 */
	void setLazyInit(boolean lazyInit);

	/**
	 * 返回这个 bean 是否应该被延迟初始化，即在启动时不急切地实例化。 仅适用于单例 bean。
	 */
	boolean isLazyInit();

	/**
	 * 设置该 Bean 依赖的所有的 Bean，bean 工厂将保证这些 bean 首先被初始化。
	 * 注意，这里的依赖不是指属性依赖(如 @Autowire 标记的)，而是 depends-on="" 属性设置的值。
	 */
	void setDependsOn(@Nullable String... dependsOn);

	/**
	 * 返回此 bean 所依赖的 bean 名称。
	 */
	@Nullable
	String[] getDependsOn();

	/**
	 * 设置此 bean 是否可以注入到其他 bean 中。只对根据类型注入有效。
	 * <p>请注意，此标志旨在仅影响基于类型的自动装配。 它不会影响按名称的显式引用，即使指定的 bean 没有被标记为自动装配候选者，也会被解析。
	 * 		因此，如果名称匹配，按名称自动装配仍然会注入一个 bean。也就是说如果根据名称注入，即使这边设置了 false，也是可以的
	 */
	void setAutowireCandidate(boolean autowireCandidate);

	/**
	 * 该 Bean 是否可以注入到其他 Bean 中，只对根据类型注入有效。
	 */
	boolean isAutowireCandidate();

	/**
	 * 设置此 bean 是否是主要的自动装配候选者。
	 * <p>如果这个值对于多个匹配候选中的一个 bean 正好是true ，它将作为一个决胜局。
	 * 即：同一接口的多个实现，如果不指定名字的话，Spring 会优先选择设置 primary 为 true 的 bean
	 */
	void setPrimary(boolean primary);

	/**
	 * 返回此 bean 是否是主要的自动装配候选者。
	 */
	boolean isPrimary();

	/**
	 * 指定要使用的工厂 bean（如果有）。 这是要在其上调用指定工厂方法的 bean 的名称。
	 *
	 * 如果该 Bean 采用工厂方法生成，指定工厂名称。
	 * 一句话就是：有些实例不是用反射生成的，而是用工厂模式生成的
	 * @see #setFactoryMethodName
	 */
	void setFactoryBeanName(@Nullable String factoryBeanName);

	/**
	 * 返回工厂 bean 名称（如果有）。
	 */
	@Nullable
	String getFactoryBeanName();

	/**
	 * 指定工厂方法（如果有）。 此方法将使用构造函数参数调用，如果没有指定则不使用任何参数。
	 * 该方法将在指定的工厂 bean（如果有）上调用，或者作为本地 bean 类上的静态方法调用。
	 *
	 * @see #setFactoryBeanName
	 * @see #setBeanClassName
	 */
	void setFactoryMethodName(@Nullable String factoryMethodName);

	/**
	 * 返回工厂方法（如果有）。
	 */
	@Nullable
	String getFactoryMethodName();

	/**
	 * 返回此 bean 的构造函数参数值。
	 * 返回的实例可以在 bean factory 后处理期间进行修改。
	 * @return  ConstructorArgumentValues 对象（从不为null ）
	 */
	ConstructorArgumentValues getConstructorArgumentValues();

	/**
	 * 如果有为此 bean 定义的构造函数参数值，则返回。
	 * @since 5.0.2
	 */
	default boolean hasConstructorArgumentValues() {
		return !getConstructorArgumentValues().isEmpty();
	}

	/**
	 * 返回要应用于 bean 的新实例的属性值。后面给 bean 注入属性值的时候会用到。
	 * 返回的实例可以在 bean factory 后处理期间进行修改。
	 *
	 * @return MutablePropertyValues 对象（从不为null ）
	 */
	MutablePropertyValues getPropertyValues();

	/**
	 * 如果有为此 bean 定义的属性值，则返回。
	 * @since 5.0.2
	 */
	default boolean hasPropertyValues() {
		return !getPropertyValues().isEmpty();
	}

	/**
	 * 设置初始化方法的名称。
	 * @since 5.1
	 */
	void setInitMethodName(@Nullable String initMethodName);

	/**
	 * 返回初始化方法的名称。
	 * @since 5.1
	 */
	@Nullable
	String getInitMethodName();

	/**
	 * 设置销毁方法的名称。
	 * @since 5.1
	 */
	void setDestroyMethodName(@Nullable String destroyMethodName);

	/**
	 * 返回销毁方法的名称。
	 * @since 5.1
	 */
	@Nullable
	String getDestroyMethodName();

	/**
	 * 为这个BeanDefinition设置角色提示。 角色提示为框架和工具提供了特定BeanDefinition的角色和重要性的指示。
	 * @since 5.1
	 * @see #ROLE_APPLICATION
	 * @see #ROLE_SUPPORT
	 * @see #ROLE_INFRASTRUCTURE
	 */
	void setRole(int role);

	/**
	 * 获取此BeanDefinition的角色提示。 角色提示为框架和工具提供了特定BeanDefinition的角色和重要性的指示。
	 * @see #ROLE_APPLICATION
	 * @see #ROLE_SUPPORT
	 * @see #ROLE_INFRASTRUCTURE
	 */
	int getRole();

	/**
	 * 设置此 bean 定义的人类可读描述。
	 * @since 5.1
	 */
	void setDescription(@Nullable String description);

	/**
	 * 返回此 bean 定义的人类可读描述。
	 */
	@Nullable
	String getDescription();


	// 只读属性

	/**
	 * 根据 bean 类或其他特定元数据，返回此 bean 定义的可解析类型。
	 * 这通常在运行时合并的 bean 定义上完全解决，但不一定在配置时定义实例上解决。
	 * @return 可解析类型（可能是{@link ResolvableType#NONE} ）
	 * @since 5.2
	 * @see ConfigurableBeanFactory#getMergedBeanDefinition
	 */
	ResolvableType getResolvableType();

	/**
	 * 返回这是否是一个Singleton ，在所有调用中返回一个单一的共享实例。
	 * @see #SCOPE_SINGLETON
	 */
	boolean isSingleton();

	/**
	 * 返回这是否为Prototype ，并为每次调用返回一个独立的实例。
	 * @since 3.0
	 * @see #SCOPE_PROTOTYPE
	 */
	boolean isPrototype();

	/**
	 * 返回此 bean 是否“抽象”，即不打算实例化。
	 */
	boolean isAbstract();

	/**
	 * 返回此 bean 定义来自的资源的描述（为了在出现错误时显示上下文）。
	 */
	@Nullable
	String getResourceDescription();

	/**
	 * 返回原始 BeanDefinition，如果没有则返回null 。
	 * 允许检索装饰的 bean 定义（如果有）。
	 * 请注意，此方法返回直接发起者。 遍历创建者链以找到用户定义的原始 BeanDefinition。
	 */
	@Nullable
	BeanDefinition getOriginatingBeanDefinition();

}
